module("Hero", package.seeall)

require("src.ui.ProgressBar")
require("src.templates.HeroTemplates")

local Hero = class("Hero")

local nilfunction = function() end

Hero = class("Hero",
    function()
        return cc.Node:create()
    end
)

Hero.__index = Hero

function create(param, corps)
    local self = Hero.new()

    self.param = param
    self.template = HeroTemplates.values[param.templateId]
    setmetatable(self.param, {__index = self.template})

    self.hp = param.maxHp
    self.corps = corps
    
    self.skills = {}
    self.nextSequnceIndex = 1

    self.hpBar = ProgressBar.create()
    self.hpBar:setMax(self.param.maxHp)
    self:addChild(self.hpBar)
    
    self.hpBar:setOpacity(0)

    self.hpBar:setPosition(0, 120)

    for k,skillid in ipairs(param.skills) do
        local skill = SkillTemplates.values[skillid]
        table.insert(self.skills, Skill.create(skill, self))
    end

    if nil ~= self then
        local function onNodeEvent(event)
            if "enter" == event then
                self:onEnter()
            end
        end

        self:registerScriptHandler(onNodeEvent)
    end

    self._elapsedTime = 2

    return self
end

function Hero:update(dt)
	if (self._status == "playSkill") then

	else
	    if (self._moveStatus == "moveforward") then
		    local x,y = self:getPosition()
		    local newPosition = cc.p(x + self.param.moveSpeed * dt, y)
		    self:setPosition(newPosition)
		elseif (self._moveStatus == "moveback") then
		    local x,y = self:getPosition()
		    local newPosition = cc.p(x - self.param.moveSpeed * dt, y)
		    self:setPosition(newPosition)
		end
	end

    if (self.beattack) then
        return
    elseif (self.moving) then
        if (self.target:getPositionX() > self:getPositionX()) then
            local x,y = self:getPosition()
            local newPosition = cc.p(x + self.param.moveSpeed * dt, y)
            self:setPosition(newPosition)
        else
            local x,y = self:getPosition()
            local newPosition = cc.p(x - self.param.moveSpeed * dt, y)
            self:setPosition(newPosition)
        end

        if (self.currentSkill) then
            self.moving = self.currentSkill:onPositionChange(self)
        end
    end

    if (self.currentSkill and not self.currentSkill:isFinished()) then
        return
    end

    self._elapsedTime = self._elapsedTime + dt
    if (self._elapsedTime >= self.param.attackSpeed) then
        local skill = self:getSkill(self.param.skillSequence[self.nextSequnceIndex])
        print("下一个技能", skill.param.name)
        if (skill) then
            skill:use()
            self.currentSkill = skill
            self.nextSequnceIndex = self.nextSequnceIndex + 1
            if (self.nextSequnceIndex > #self.param.skillSequence) then
                self.nextSequnceIndex = 1
            end
        end
        self._elapsedTime = 0
    end

    self:reSortHero()

end

function Hero:reSortHero()
    local winHeight = cc.Director:getInstance():getWinSize().height
    for k, hero in ipairs(self.corps.heros) do
        hero:getParent():reorderChild(hero, winHeight - hero:getPositionY())
    end
end

function Hero:getSkill(skillid)
    for k,v in ipairs(self.skills) do
        if (v.param.id == skillid) then
            return v
        end
    end
end

function Hero:onEnter()
    print("onEnter")
	self:preloadRes()

	function update(dt)
		self:update(dt)
	end

    self:scheduleUpdateWithPriorityLua(update,1)
end

function Hero:getAttackPoint(  )
   local bone = self._armature:getBone(self.param.attackBone)
   if (bone) then
        return cc.p(
                self:getPositionX() + 30  * self:getScaleX(),
                self:getPositionY() + 80 * self:getScaleY()
            )
    else
        return cc.p(self:getPosition())
    end
end

function Hero:turnTo(direction)
	if (direction == "left") then
		self:setScaleX(-1)
		self.hpBar:setScaleX(-1)
	else
		self:setScaleX(1)
		self.hpBar:setScaleX(1)
	end
end

function Hero:preloadRes()
    ccs.ArmatureDataManager:getInstance():addArmatureFileInfo(self.param.armaResPath)
    self._armature = ccs.Armature:create(self.param.armaName)
   -- self._armatureShadow = ccs.Armature:create(self.param.armaName)
   	self._armature:setScale(self.param.armaScale)
    self:addChild(self._armature)
    --self:addChild(_armatureShadow)
    
end

function Hero:walkingTo(target)
    self.moving = true
    self.target = target

    self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
end

function Hero:playSkill(skillid)
	local skill = self.skills[skillid]
	if (not skill) then
		return
	end

	local function animationEvent(armatureBack,movementType,movementID)
	    local id = movementID
	    if movementType == ccs.MovementEventType.complete then
	        if (self._moveStatus == nil) then
	        	self._armature:getAnimation():playWithIndex(self.param.actionMap.standby)
	        else
	        	self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
	        end
	        self._status = nil
	    end
	end

	self._status = "playSkill"
	self._armature:getAnimation():setMovementEventCallFunc(animationEvent)
	self._armature:getAnimation():playWithIndex(skill.action)
end

function Hero:playAction(actionId)
    local function animationEvent(armatureBack,movementType,movementID)
        local id = movementID
        if movementType == ccs.MovementEventType.complete then
            if (self._moveStatus == nil) then
                self._armature:getAnimation():playWithIndex(self.param.actionMap.standby)
            else
                self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
            end
            self._status = nil
        end
    end

    self._status = "playSkill"
    self._armature:getAnimation():setMovementEventCallFunc(animationEvent)
    self._armature:getAnimation():playWithIndex(skill.action)
end

function Hero:attacked(skill, effectValue)
    if (not self:isAlive()) then
        return
    end

    local function animationEvent(armatureBack,movementType,movementID)
        local id = movementID
        if movementType == ccs.MovementEventType.complete then
            self._armature:getAnimation():setMovementEventCallFunc(nilfunction)
            self.beattack = nil
            if (self.moving) then
                self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
            else
                self._armature:getAnimation():playWithIndex(self.param.actionMap.standby)
            end
        end
    end

    local criteScale = 0.5
    if (skill:isCrit()) then
        criteScale = 0.8
    end

    function removeNode(node)
        node:removeFromParent()
    end

    local label = cc.LabelAtlas:_create("", "res/red.png", 35, 48, 48)

    label:setAnchorPoint(cc.p(0.5, 0.5));
    label:setPosition(self:getPosition());
    label:setPositionY(label:getPositionY() + 160 * self:getScaleY());
    label:setScale(0.1);
    

    label:runAction(cc.Sequence:create(cc.EaseElasticOut:create(cc.ScaleTo:create(0.2, criteScale)),
                                       cc.Spawn:create(cc.MoveBy:create(1, cc.p(0, 50)), cc.FadeOut:create(1)),
                                       cc.RemoveSelf:create()
                                       )
                    )


    cc.Director:getInstance():getRunningScene():addChild(label, 99999);

    if (effectValue < 0) then
        label:setString(string.format(":%d", math.abs(effectValue)));
        self.hp = self.hp + effectValue
        self.hpBar:setValue(self.hp, 0, 0.8)
        self.hpBar:stopAllActions()
        self.hpBar:runAction(cc.Sequence:create(cc.FadeIn:create(0.2), cc.DelayTime:create(1), cc.FadeOut:create(1)))
        if (self.hp <= 0) then
            self:dying()
        else
            if (skill:isCrit()) then
                self._armature:getAnimation():playWithIndex(self.param.actionMap.attacked)
                self._armature:getAnimation():setMovementEventCallFunc(animationEvent)
                self.beattack = true
                if (not self.moving) then
                    if (self.currentSkill) then
                        self.currentSkill = nil
                    end
                end
            end
        end
    else
    end
end

function Hero:dying()
    local function animationEvent(armatureBack,movementType,movementID)
        local id = movementID
        if movementType == ccs.MovementEventType.complete then
            self._armature:getAnimation():setMovementEventCallFunc(nilfunction)
            self._armature:runAction(cc.Sequence:create(cc.DelayTime:create(1), cc.FadeOut:create(2)))
            self.hpBar:stopAllActions()
            self.hpBar:runAction(cc.Sequence:create(cc.DelayTime:create(1), cc.FadeOut:create(1)))
--            self.hpBar:setOpacity(0)
        end
    end

    self._armature:getAnimation():playWithIndex(self.param.actionMap.die)
    self._armature:getAnimation():setMovementEventCallFunc(animationEvent)
    self:unscheduleUpdate()

    self.corps:onHeroDie(self)
end

function Hero:onVictory()
    self._armature:getAnimation():playWithIndex(self.param.actionMap.win)
end

function Hero:moveBack()
    if (self._status == nil) then
	   self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
    end
	self._moveStatus = "moveback"
end

function Hero:moveForward()
    if (self._status == nil) then
	   self._armature:getAnimation():playWithIndex(self.param.actionMap.move)
    end
	self._moveStatus = "moveforward"
end

function Hero:standby()
    if (self._status == nil) then
	   self._armature:getAnimation():playWithIndex(self.param.actionMap.standby)
    end
	self._moveStatus = nil
end

function Hero:isAlive()
	return self.hp > 0
end